.TH IOPROC 3
.SH NAME
closeioproc,
iocall,
ioclose,
iointerrupt,
iodial,
ioopen,
ioproc,
ioread,
ioread9pmsg,
ioreadn,
iorecvfd,
iosendfd,
iosleep,
iowrite \- slave I/O processes for threaded programs
.SH SYNOPSIS
.PP
.de XX
.ift .sp 0.5
.ifn .sp
..
.EX
.ta \w'Ioproc* 'u
#include <u.h>
#include <libc.h>
#include <thread.h>
.sp
typedef struct Ioproc Ioproc;
.sp
Ioproc*	ioproc(void);
.XX
int	ioclose(Ioproc *io, int fd);
int	iodial(Ioproc *io, char *addr, char *local, char *dir, char *cdfp);
int	ioopen(Ioproc *io, char *file, int omode);
long	ioread(Ioproc *io, int fd, void *a, long n);
int	ioread9pmsg(Ioproc *io, int fd, void *a, uint n);
long	ioreadn(Ioproc *io, int fd, void *a, long n);
int	iorecvfd(Ioproc *io, int socket);
int	iosendfd(Ioproc *io, int socket, int fd);
int	iosleep(Ioproc *io, long milli);
long	iowrite(Ioproc *io, int fd, void *a, long n);
.XX
void	iointerrupt(Ioproc *io);
void	closeioproc(Ioproc *io);
.XX
long	iocall(Ioproc *io, long (*op)(va_list *arg), ...);
.EE
.SH DESCRIPTION
.PP
These routines provide access to I/O in slave procs.
Since the I/O itself is done in a slave proc, other threads
in the calling proc can run while the calling thread
waits for the I/O to complete.
.PP
.I Ioproc
forks a new slave proc and returns a pointer to the
.B Ioproc
associated with it.
.I Ioproc
uses
.I mallocz
and
.IR proccreate ;
if either fails, it calls
.I sysfatal
rather than return an error.
.PP
.IR Ioclose ,
.IR iodial ,
.IR ioopen ,
.IR ioread ,
.IR ioread9pmsg ,
.IR ioreadn ,
.IR iorecvfd ,
.IR iosendfd ,
.IR iosleep ,
and
.I iowrite
execute the
similarly named library or system calls
(see
.IR close (2),
.IR dial (3),
.IR open (3),
.IR read (3),
.IR fcall (3),
.IR sendfd (3),
and
.IR sleep (3))
in the slave process associated with
.IR io .
It is an error to execute more than one call
at a time in an I/O proc.
.PP
.I Iointerrupt
interrupts the call currently executing in the I/O proc.
If no call is executing,
.IR iointerrupt
is a no-op.
.PP
.I Closeioproc
terminates the I/O proc and frees the associated
.B Ioproc .
.PP
.I Iocall
is a primitive that may be used to implement
more slave I/O routines.
.I Iocall
arranges for
.I op
to be called in
.IR io 's
proc, with
.I arg
set to the variable parameter list,
returning the value that
.I op
returns.
.SH EXAMPLE
Relay messages between two file descriptors,
counting the total number of bytes seen:
.IP
.EX
.ta +\w'xxxx'u +\w'xxxx'u +\w'xxxx'u
int tot;

void
relaythread(void *v)
{
	int *fd, n;
	char buf[1024];
	Ioproc *io;

	fd = v;
	io = ioproc();
	while((n = ioread(io, fd[0], buf, sizeof buf)) > 0){
		if(iowrite(io, fd[1], buf, n) != n)
			sysfatal("iowrite: %r");
		tot += n;
	}
	closeioproc(io);
}

void
relay(int fd0, int fd1)
{
	int fd[4];

	fd[0] = fd[3] = fd0;
	fd[1] = fd[2] = fd1;
	threadcreate(relaythread, fd, 8192);
	threadcreate(relaythread, fd+2, 8192);
}
.EE
.LP
The two
.I relaythread
instances are running in the same proc, so the
common access to
.I tot
is safe.
.PP
Implement
.IR ioread :
.IP
.EX
static long
_ioread(va_list *arg)
{
	int fd;
	void *a;
	long n;

	fd = va_arg(*arg, int);
	a = va_arg(*arg, void*);
	n = va_arg(*arg, long);
	return read(fd, a, n);
}

long
ioread(Ioproc *io, int fd, void *a, long n)
{
	return iocall(io, _ioread, fd, a, n);
}
.EE
.SH SOURCE
.B \*9/src/libthread
.SH SEE ALSO
.IR dial (3),
.IR open (3),
.IR read (3),
.IR thread (3)
.SH BUGS
.I Iointerrupt
is currently unimplemented.
.PP
C99 disallows the use of pointers to
.BR va_list .
This interface will have to change to
use pointers to a structure containing a 
.BR va_list .
